/*
** Copyright (c) K-Marrade
** All rights reserved.
**
** write.c : Contains the syscall write ().
**
** Use with caution.
**
*/
#include "kstd.h"

#define K_TEXT_LINE_NB 25
#define K_TEXT_COLUMN_NB 80
#define K_TEXT_BUFFER_SIZE 80*25*2
#define K_BUFFER_ADDR 0xB8000

static struct {
    char	line;
    char	column;
} cursor_position;

static char text_color = 0x07;

static void clear_screen (void)
{
  int *b_addr = (void*) K_BUFFER_ADDR;
  int i = 0;

  for (i = 0; i < K_TEXT_BUFFER_SIZE; i++)
    b_addr[i] = 0;
}

static void init (void)
{
  cursor_position.line = 0;
  cursor_position.column = 0;

  text_color = CONS_WHITE;

  clear_screen ();
}

static inline void scroll (void)
{
  int i = 0, j;

  for (; i < (K_TEXT_LINE_NB - 1); i++)
    for (j = 0; j < (K_TEXT_COLUMN_NB * 2); j++)
      ((char*) K_BUFFER_ADDR)[i * K_TEXT_COLUMN_NB * 2 + j] =
	((char*) K_BUFFER_ADDR)[(i + 1) * K_TEXT_COLUMN_NB * 2 + j];

  for (j = 0; j < (K_TEXT_COLUMN_NB * 2); j++)
    ((char*) K_BUFFER_ADDR)[i * K_TEXT_COLUMN_NB * 2 + j] = 0;
}

static void update_position (void)
{
  if ((cursor_position.column + 1) >= K_TEXT_COLUMN_NB)
    {
      if (cursor_position.line + 1 >= K_TEXT_LINE_NB)
	scroll ();
      else
	cursor_position.line += 1;
      cursor_position.column = 0;
    }
  else
    cursor_position.column += 1;
}

static void putc (char c)
{
  if (c == '\n')
    cursor_position.column = K_TEXT_COLUMN_NB;
  else
    {
      if (c == '\t')
	cursor_position.column += 7;
      else
	{
	  int pos = ((cursor_position.line * K_TEXT_COLUMN_NB) +
		     cursor_position.column) * 2;

	  ((char*) K_BUFFER_ADDR)[pos] = c;
	  ((char*) K_BUFFER_ADDR)[pos + 1] = text_color;
	}
    }
  update_position ();
}

int write (const char* s, size_t length)
{
  size_t i;
  unsigned char c;

  for (i = 0; i < length; i++)
    {
      c = s[i];
      if ((c == CONS_ESCAPE) && (i + 1 < length))
	switch ((unsigned char) s[i + 1])
	  {

	  case CONS_CLEAR:
	    init ();
	    i++;
	    break;

	  case CONS_COLOR:
	    if (i + 2 < length)
	      {
		text_color = s[i + 2];
		i += 2;
	      }
	    break;

	  case CONS_SETX:
	    if (i + 2 < length)
	      {
		cursor_position.column = s[i + 2];
		i += 2;
	      }
	    break;

	  case CONS_SETY:
	    if (i + 2 < length)
	      {
		cursor_position.line = s[i + 2];
		i += 2;
	      }
	    break;

	  default: break;
	  }
      else
	putc (s[i]);
    }

  return 0;
}
